package com.duobaoyu.dby.supply.biz.strategy;


import com.alibaba.fastjson.JSON;
import com.duobaoyu.dby.channel.adapter.enums.biz.message.MessageStatusEnum;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.enums.LockKeys;
import com.duobaoyu.dby.supply.biz.enums.RedisKeys;
import com.duobaoyu.dby.supply.common.biz.bo.message.ChannelMessageBO;
import com.duobaoyu.dby.supply.core.cache.service.RedissonService;
import com.duobaoyu.dby.supply.core.framework.strategy.AbstractStrategy;
import com.duobaoyu.dby.supply.db.constant.SupplyMapperConstant;
import com.duobaoyu.dby.supply.db.entity.message.ChannelMessageOrder;
import com.duobaoyu.dby.supply.db.helper.DynamicTableNameHelper;
import com.duobaoyu.dby.supply.db.repository.message.ChannelMessageRepository;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName AbstractChannelMessageAsyncHandler
 * @Description 抽象的渠道消息异步处理器
 * @createTime 11:38:00 2023/09/28
 */
@Slf4j
public abstract class AbstractChannelMessageAsyncHandler extends AbstractStrategy<ChannelMessageBO, Boolean> {

	@Resource
	private ChannelMessageRepository channelMessageRepository;
	@Resource
	private RedissonService redissonService;

	protected Set<String> channelCodes() {
		return Collections.emptySet();
	}

	protected Set<Integer> bizMessageTypes() {
		return Collections.emptySet();
	}

	@Override
	public boolean support(Object... args) {
		if (ObjectUtils.isNotEmpty(args) && CollectionUtils.isNotEmpty(this.channelCodes()) &&
				CollectionUtils.isNotEmpty(this.bizMessageTypes()) && args.length == CommonConstants.TWO) {
			return Arrays.stream(args)
					.filter(item -> item instanceof String)
					.anyMatch(item -> this.channelCodes().contains((String) item)) &&
					Arrays.stream(args)
							.filter(item -> item instanceof Integer)
							.anyMatch(item -> this.bizMessageTypes().contains((Integer) item));
		}
		return false;
	}

	@Override
	protected final Object beforeHandler(ChannelMessageBO channelMessage) {
		String suffix = DynamicTableNameHelper.getRequestData(SupplyMapperConstant.CHANNEL_MESSAGE_TABLE_NAME);
		if (StringUtils.isBlank(suffix)) {
			Map<String, Object> map = Maps.newHashMap();
			map.put(SupplyMapperConstant.CHANNEL_MESSAGE_TABLE_NAME, SupplyMapperConstant.CHANNEL_MESSAGE_ORDER_SUFFIX);
			DynamicTableNameHelper.setRequestData(map);
		}
		return super.beforeHandler(channelMessage);
	}

	@Override
	protected Boolean handler(ChannelMessageBO channelMessage, Object beforeResult) {
		if (EnumUtils.eq(MessageStatusEnum.SUCCESS, channelMessage.getStatus())) {
			return Boolean.TRUE;
		}
		if(log.isDebugEnabled()) {
			log.debug("message:{},data:{}","message消息", JSON.toJSONString(channelMessage));
		}
		return this.executeHandler(channelMessage, beforeResult);
	}

	protected abstract Boolean executeHandler(ChannelMessageBO channelMessage, Object beforeResult);

	@Override
	protected final Object afterHandler(ChannelMessageBO channelMessage, Boolean result) {
		if (Optional.ofNullable(result).orElse(Boolean.FALSE)) {
			return channelMessageRepository.updateMessageStatusById(channelMessage.getChannelMessageId(), MessageStatusEnum.SUCCESS.getValue(), ChannelMessageOrder.class);
		} else {
			return channelMessageRepository.updateMessageStatusById(channelMessage.getChannelMessageId(), MessageStatusEnum.FAIL.getValue(), ChannelMessageOrder.class);
		}
	}

	@Override
	protected Boolean exceptionHandler(ChannelMessageBO channelMessage, Throwable e) {
		channelMessageRepository.updateMessageStatusById(channelMessage.getChannelMessageId(), MessageStatusEnum.FAIL.getValue(), ChannelMessageOrder.class);
		return super.exceptionHandler(channelMessage, e);
	}

	@Override
	protected final Object finallyHandler(ChannelMessageBO channelMessage, Boolean aBoolean) {
		DynamicTableNameHelper.removeRequestData();
		return super.finallyHandler(channelMessage, aBoolean);
	}

	@Override
	public final Boolean strategyHandler(ChannelMessageBO channelMessage) {
		String lockKey = LockKeys.CHANNEL_ASYNC_MESSAGE.formatKey(channelMessage.getChannelMessageId());
		return redissonService.tryLock(RedisKeys.LOCK_REDIS.formatKey(lockKey),() -> null, () -> super.strategyHandler(channelMessage));
	}
}
